home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr08 / arcdib20.zip / YOURCOMP.PAS < prev   
Pascal/Delphi Source File  |  1993-06-17  |  11KB  |  276 lines

  1. { This is an example of exporting your own compression algorithm into ARCDIB
  2.   using a Turbo Pascal DLL. You can use this code as a shell by replacing
  3.   the "YouCompress" and "YourDeCompress" functions with your own algorithms
  4.   for compression and decompression respectively. The function exported by
  5.   the DLL is "MyComp".
  6.  
  7. function MyComp(var IMAGEHANDLE: THandle;
  8.                 var BITSSIZE: LongInt;
  9.                     COMPRESS: Boolean): Boolean ; export;
  10.  
  11.   Its name and parameters must not change since ARCDIB expects it that way.
  12.   As you can see, the function returns TRUE or FALSE depending on its sucess
  13.   - determined by you. The three parameters are:
  14.  
  15.    IMAGEHANDLE: a Windows Global Handle to a memory block containing either
  16.                 the uncompressed or compressed bytes of the bitmap image.
  17.  
  18.       BITSSIZE: the size of the bitmap bytes ("bits") before being
  19.                 compressed and the size of the compressed bits when
  20.                 expanding.
  21.  
  22.       COMPRESS: TRUE if compressing, FALSE if decompressing. If compressing,
  23.                 IMAGEHANDLE refers to a block of uncompressed bitmap "bits"
  24.                 - the same as to "bits" of a Windows DIB. If decompressing,
  25.                 then IMAGEHANDLE refers to the block of memory returned as
  26.                 a result of a previous compression.
  27.  
  28. THE CONCEPT IS THIS:
  29.   Upon entry into "MyComp" you obtain a pointer to the memory block referred
  30.   to by IMAGEHANDLE. You then create another global Handle of size BITSSIZE
  31.   to use as output of your compression/decompression routine. Obtain a
  32.   pointer to this NewHandle with GlobalLock. Then, you pass each byte
  33.   in IMAGEHANDLE (in this case, one at a time) to either YourCompress or
  34.   YourDeCompress routines depending on the COMPRESS flag. In each of those
  35.   routines, you write the output to the new memory block you created
  36.   referred to by NewHandle. Finally, you reallocate NewHandle to the size
  37.   resulting from the compression/decompression (ie keep track of the number
  38.   of bytes written) and get rid the passed in IMAGEHANDLE with GlobalFree
  39.   and reassign it to Newhandle. Always pass the resulting size of the
  40.   compressed (or expanded) bytes in BITSSIZE!
  41.   Keep the following in mind:
  42.  
  43.          1. This alorithm ASSUMES the result of the compression will require
  44.             a smaller block of memory than the original. For decompression,
  45.             the result should equal the original (obiviously) and the
  46.             GlobalReAlloc call is actually redundant because in both cases
  47.             you create Newhandle using the original (uncompressed) size.
  48.  
  49.          2. You must keep track of the number of bytes written to the new
  50.             handle in order to determine its new size for reallocation.
  51.  
  52.          3. Don't forget to "unlock" the new handle before returning from
  53.             the function.
  54.  
  55.          4. If the function returns FALSE, ARCDIB flags the bitmap as being
  56.             in compressed form and will therefore call MyComp again to
  57.             uncompress the "bits" before displaying.
  58.  
  59.          5. If you return FALSE during compression, ARCDIB will just
  60.             assume something went wrong in your compression and EXPECTS
  61.             IMAGEHANDLE refer to the same block of uncompressed bytes that
  62.             it did before the call! This could be disastorous if you somehow
  63.             corrupt the original data so be careful not to. Worse yet, on
  64.             decompression, returning FALSE leaves ARCDIB on a limb because,
  65.             presumably, it passed in successfully compressed data and you
  66.             are now telling it that there's no way back...we're doomed.
  67.  
  68.          6. Keep in mind that if the size of the bitmap is greater that
  69.             64K, you must make your code aware of the segment boundries
  70.             that you'll eventually cross reading and (possibly) writing
  71.             from/to the memory blocks. This is illustrated in the example
  72.             by creating a variant record type for a special far pointer
  73.             that can be safely incremented using a Windows call to AHINC().
  74.  
  75.      ***** Thanks to Tom Swam (the Charles Petzold of TPW) and his book
  76.             "Turbo Pascal for Windows 3.0 Programming" for this and MANY
  77.             other useful tricks.
  78.  
  79.          6. When compressing/decompressing a bitmap in ARCDIB, a status
  80.             box appears showing percent completion. In your case, I have
  81.             no way of knowing this info so the box just kind of sits
  82.             there and says "Please wait..". In the future, I'll provide
  83.             some type of Callback function so that you can update the
  84.             status yourself - or least the OPTION to, since most compression
  85.             purest loaf the idea of delaying their algorithm unecessarily.
  86.  
  87.          7. Again, the library (DLL) name MUST remain "YourComp" and the
  88.             compression function name MUST remain "MyComp" with the SAME
  89.             parameters and exported index.
  90.  
  91.                                           Sine Labore Nihil...
  92.  
  93.  
  94. Brendan Daunt
  95. BETTER MAPS
  96. (619) 598-1323
  97. 76307,2411
  98.                                                                             }
  99.  
  100. {***************************************************************************}
  101. library YourComp; { Don't change this name }
  102.  
  103. uses WinTypes, WinProcs;
  104.  
  105. { Windows function for calculating pointer offsets safely }
  106. Procedure AHIncr; far; external 'KERNEL' index 114;
  107.  
  108. { Variant record type for a far pointer to step through memory blocks that
  109.   may cross segment boundries. }
  110. Type
  111.  LongType = record
  112.   case word of
  113.    0: (Ptr: Pointer);
  114.    1: (Long: LongInt);
  115.    2: (Lo: Word; Hi: Word);
  116.   end;
  117.  
  118. { Global variables }
  119. Var h,                   { Temporary handle                              }
  120.     NewHandle: THandle;  { New handle refers to compressed "bits"        }
  121.     OldBits,             { Pointer to memory block in IMAGEHANDLE        }
  122.     NewBits  : Pointer;  { Pointer to memory block in NewHandle          }
  123.     NewSize  : LongInt;  { Resulting size of NewHandle after compression }
  124.  
  125. { These are dummy procedures (stubs) provided to illustrate how you might
  126.   implement your own compress/decompress algorithms.
  127.  
  128.   They are called from the exported function "MyComp" with a Byte type
  129.   parameter which represents an uncompressed/compressed byte in the
  130.   original IMAGEHANDLE passed to "MyComp".
  131.  
  132.   Be sure to write the output of either function to the global memory
  133.   block in NewHandle and also keep track of the numbers of bytes written  }
  134.  
  135.  Var
  136.   ToBits,
  137.   ToStart,
  138.   ToAddr    : LongType;  { Special far pointer records     }
  139.  
  140. procedure YourCompress(InByte: Byte);
  141. {}
  142.  Begin
  143.   { ...compress InByte somehow  }
  144.  
  145.   ToAddr.Hi := ToBits.Hi + ( ToStart.Hi * Ofs(AHIncr));
  146.   ToAddr.Lo := ToStart.LO;
  147.   Byte(ToAddr.Ptr^) := InByte;
  148.   Inc(ToStart.Long);
  149.  
  150.   Inc(NewSize);
  151.  End;
  152.  
  153. procedure YourDeCompress(InByte: Byte);
  154. {}
  155.  Begin
  156.   { ...decompress InByte somehow }
  157.  
  158.   ToAddr.Hi := ToBits.Hi + ( ToStart.Hi * Ofs(AHIncr));
  159.   ToAddr.Lo := ToStart.LO;
  160.   Byte(ToAddr.Ptr^) := InByte;
  161.   Inc(ToStart.Long);
  162.  
  163.   Inc(NewSize);
  164.  End;
  165.  
  166.  
  167. { This is the only function exported by YourComp.DLL - header and
  168.   results must remain the same (see above). }
  169.  
  170. function MyComp(var IMAGEHANDLE: THandle; 
  171.                 var BITSSIZE: LongInt;
  172.                     COMPRESS: Boolean) : Boolean ; export;
  173. {}
  174.  Var
  175.   OneByte     : Byte;     { Holds a byte to be compressed/decompressed }
  176.   ImageSize,              { Size of IMAGEHANDLE                        }
  177.   OldPtrOffSet: LongInt;  { Pointer offset into IMAGEHANDLE            }
  178.   FromBits,
  179.   FromStart,
  180.   FromAddr    : LongType;  { Special far pointer records     }
  181.  
  182.  Begin
  183.   MessageBox(GetActiveWindow, 'Dummy compress DLL for instructional purposes only.', 'YourComp.DLL', mb_IconExclamation);
  184.   MyComp  := False;
  185.   NewSize := 0;       { Contains the number of bytes written to NewHandle }
  186.  
  187. { Get a pointer to the original handle }
  188.   OldBits := GlobalLock(IMAGEHANDLE);
  189.   If OldBits = nil Then
  190.    Begin
  191.     MessageBox(GetActiveWindow, 'OldBits = nil', 'MyComp ERROR',
  192.                                  mb_TaskModal or mb_Ok);
  193.     Exit;
  194.    End;
  195.  
  196. { Create new memory block (NewHandle) - same size as uncompressed block }
  197.   NewHandle := GlobalAlloc(gmem_Moveable or gmem_ZeroInit, BITSSIZE);
  198.   If NewHandle = 0 Then
  199.    Begin
  200.     MessageBox(GetActiveWindow, 'NewHandle = 0', 'MyComp ERROR',
  201.                                  mb_TaskModal or mb_Ok);
  202.     Exit;
  203.    End;
  204.  
  205. { Get a pointer to the new handle }
  206.   NewBits := GlobalLock(NewHandle);
  207.   If NewBits = nil Then
  208.    Begin
  209.     MessageBox(GetActiveWindow, 'NewBits = nil', 'MyComp ERROR',
  210.                                  mb_TaskModal or mb_Ok);
  211.     GlobalFree(NewHandle);
  212.     Exit;
  213.    End;
  214.  
  215.   FromStart.Long := 0;       { Initial pointer offset into IMAGEHANDLE      }
  216.   FromBits.Ptr   := OldBits; { Use LongType pointer for segment "awareness" }
  217.  
  218.   ToStart.Long := 0;       { Initial pointer offset into NewHandle        }
  219.   ToBits.Ptr   := NewBits; { Use LongType pointer for segment "awareness" }
  220.  
  221. { Process each byte in IMAGEHANDLE }
  222.   ImageSize := GlobalSize(IMAGEHANDLE);
  223.   For OldPtrOffset := 0 to ImageSize-1 Do
  224.    Begin
  225.    { Calculate the pointer offset }
  226.     FromAddr.Hi := FromBits.Hi + ( FromStart.Hi * Ofs(AHIncr));
  227.     FromAddr.Lo := FromStart.LO;
  228.  
  229.    { Get a byte from the original memory block in IMAGEHANDLE }
  230.     OneByte := Byte(FromAddr.Ptr^);
  231.  
  232.    { Now call your compression or decompression routine with OneByte }
  233.     If Compress Then
  234.      YourCompress(OneByte)     { procedure of your choice for compression   }
  235.     Else
  236.      YourDeCompress(OneByte);  { procedure of your choice for decompression }
  237.  
  238.    { Increment the pointer offset }
  239.     Inc(FromStart.Long);
  240.    End; { For each byte in IMAGEHANDLE }
  241.  
  242. { Unlock the NewHandle and attempt to reallocate it with new size }
  243.   GlobalUnlock(NewHandle);
  244.   h := GlobalReAlloc(NewHandle, NewSize, gmem_Moveable or gmem_ZeroInit);
  245.   if (h <> 0) Then
  246.    Begin
  247.     GlobalUnlock(IMAGEHANDLE);
  248.     GlobalFree(IMAGEHANDLE);     { Get rid of original handle to "bits" }
  249.     NewHandle := h;              { Assign NewHandle to reallocated block}
  250.    End
  251.   Else                           { GlobalReAlloc failed - abort }
  252.    Begin
  253.     GlobalFree(NewHandle);       { Free the new handle }
  254.     MessageBox(GetActiveWindow, 'Could realloc NewHandle', 'MyComp ERROR',
  255.                                  mb_TaskModal or mb_Ok);
  256.     Exit;
  257.    End;
  258.  
  259. { Success }
  260.   BITSSIZE    := NewSize;
  261.   ImageHandle := NewHandle;
  262.   MyComp      := True;
  263.  
  264.  End; { MyComp }
  265.  
  266. {- List exported routines }
  267.  
  268. exports
  269.  
  270.   MyComp   index 3;          { Export MyComp with index of 3 }
  271.  
  272. BEGIN
  273. END. { YourComp DLL }
  274.  
  275.  
  276.